package com.qipay.order.service.impl;

import com.qipay.baas.model.Cp;
import com.qipay.baas.model.Order;
import com.qipay.baas.model.OrderExample;
import com.qipay.baas.model.SpChannel;
import com.qipay.cp.CpService;
import com.qipay.cpaccount.CpAccountService;
import com.qipay.mapper.OrderMapper;
import com.qipay.notify.NotifyLogService;
import com.qipay.order.config.OrderSettleStateEnum;
import com.qipay.order.config.OrderStateEnum;
import com.qipay.order.service.OrderService;
import com.qipay.order.vo.*;
import com.qipay.qipay.QipayTradlogService;
import com.qipay.scalar.type.ChannelTypeEnum;
import com.qipay.sp.SpChannelRuleService;
import com.qipay.sp.SpChannelService;
import com.qipay.sp.SpService;
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import java.io.IOException;
import java.math.BigDecimal;
import java.util.*;

/**
 * Creator: Yao
 * Date:    2017/9/21
 * For:
 * Other:
 */
@Service
public class OrderServiceImpl implements OrderService {

    protected final Log logger = LogFactory.getLog(this.getClass());
    private static Integer count = 9999;

    @Autowired
    OrderMapper orderMapper;

    @Autowired
    CpAccountService cpAccountService;

    @Autowired
    QipayTradlogService qipayTradlogService;

    @Autowired
    NotifyLogService notifyLogService;

    @Autowired
    SpChannelService spChannelService;

    @Autowired
    CpService cpService;

    @Autowired
    SpService spService;

    @Autowired
    SpChannelRuleService spChannelRuleService;

    @Override
    public Long sumOrderByCp(Long cpId) {
        return orderMapper.sumOrderByCp(cpId);
    }

    @Override
    public Long sumOrderBySpUser(String sp_user_name,String form,String to) {
        return orderMapper.sumOrderBySpUser(sp_user_name,form,to);
    }

    @Override
    public String createOrder() {
        return UUID.randomUUID().toString().replace("-", "");
    }

    @Override
    public int randomDecrease(int max) {
        if(max<=0)return 0;
        else
        return (int)(Math.random()*(max-1))+1;
    }

    @Override
    public synchronized String  createOrder(int length) {
        if(count>=99999)count=9999;
        count++;
        if(length>17){
            return DateFormatUtils.format(new Date(),"yyyyMMddHHmmss") + count.toString();
        }else {
            return DateFormatUtils.format(new Date(),"yyyyMMdd") + count.toString();
            //return  RandomStringUtils.randomAlphanumeric(length);
        }
    }

    @Override
    public OrderSumVo sumOrder(String querysql) {
        return orderMapper.sumOrder(querysql);
    }

    @Override
    public long countBy(String querysql) {
        return orderMapper.countBy(querysql);
    }
    @Override
    public long amountCount(String querysql) {
        return orderMapper.amountCount(querysql);
    }
    @Override
    public long feeCount(String querysql) {
        return orderMapper.feeCount(querysql);
    }

    @Override
    public List<OrderListItem> listBy(String querysql,Object offset,Object rowss) {
        return orderMapper.listBy(querysql,offset,rowss);
    }

    @Override
    public List<CpTjVo> listCp0Tj(String from, String to, Long cpid) {
        return orderMapper.listCp0Tj(from,to,cpid);
    }

    @Override
    public List<SpTjVo> listSp0Tj(String from, String to,Long spid) {
        return orderMapper.listSp0Tj(from,to,spid);
    }

    @Override
    public List<ChannelTjVo> listChannel0Tj(String from, String to,int channelid) {
        return orderMapper.listChannel0Tj(from,to,channelid);
    }


    @Override
    public List<ChannelSpTjVo> listChannelSp0Tj(String from, String to,String spid,int channelid) {
        return orderMapper.listChannelSp0Tj(from, to,spid,channelid);
    }

    @Override
    public List<Cp_SpTjVo> listCp_Sp0Tj(String from, String to,String  cpid,int channelid) {
        return orderMapper.listCp_Sp0Tj(from, to,cpid,channelid); }

    @Override
    public Order get(Long id) {
        return orderMapper.selectByPrimaryKey(id);
    }

    @Override
    @Transactional
    public Order update(Order order) {

        // check
        Assert.notNull(order, "订单信息为空");

        orderMapper.updateByPrimaryKey(order);
        return order;
    }

    @Override
    @Transactional
    public boolean modify(Order order) {

        // check
        Assert.notNull(order, "订单信息为空");

        return orderMapper.updateByPrimaryKey(order) > 0;
    }

    @Override
    public Order insert(Order order) {
        orderMapper.insert(order);
        order.getId();
        return order;
    }

    @Override
    public Order getByCpidAndOutTradeNo(Long cpid, String outTradeNo) {
        return orderMapper.getByCpidAndOutTradeNo(cpid, outTradeNo);
    }

    @Override
    public Order getByCpidAndTradeNo(Long cpid, String tradeNo) {
        OrderExample orderExample = new OrderExample();
        orderExample.setLimit(1);
        orderExample.createCriteria().andCpIdEqualTo(cpid).andTradeNoEqualTo(tradeNo);
        List<Order> orders = orderMapper.selectByExample(orderExample);
        if (orders == null || orders.size() == 0) {
            return null;
        }
        return orders.get(0);
    }

    @Override
    public Order getBySpMchIdAndSpTradeNo(String spMchid, String spTradeNo) {
        OrderExample orderExample = new OrderExample();
        orderExample.setLimit(1);
        orderExample.createCriteria().andSpMchIdEqualTo(spMchid).andSpTradeNoEqualTo(spTradeNo);
        List<Order> orders = orderMapper.selectByExample(orderExample);
        if (orders == null || orders.size() == 0) {
            return null;
        }
        return orders.get(0);
    }

    @Override
    public Order getByTradeNo(String tradeNo) {
        OrderExample orderExample = new OrderExample();
        orderExample.setLimit(1);
        orderExample.createCriteria().andTradeNoEqualTo(tradeNo);
        List<Order> orders = orderMapper.selectByExample(orderExample);
        if (orders == null || orders.size() == 0) {
            return null;
        }
        return orders.get(0);
    }

    @Override
    @Transactional
    public Order setOrderSuccess(String tradeNo) {
        Order order = getByTradeNo(tradeNo);
        Assert.notNull(order, "找不到订单信息");

        if (Objects.equals(order.getState(), OrderStateEnum.SUCCESS.getType())) {
            return order;
        }

        order.setState(OrderStateEnum.SUCCESS.getType());
        order.setFinishTime(new Date());
        update(order);

        return order;
    }

    @Transactional
    @Override
    public Order setOrderSuccess(Long orderId, String spTradeNo) throws IOException {
        Assert.notNull(orderId, "找不到订单信息");

        Order order = get(orderId);
        return setOrderSuccess(order, spTradeNo);
    }

    @Transactional
    @Override
    public Order setOrderSuccess(Order order, String spTradeNo) throws IOException {
        Assert.notNull(order, "找不到订单信息");
        if (Objects.equals(order.getState(), OrderStateEnum.SUCCESS.getType())) {
            return order;
        }

        Assert.isTrue(Objects.equals(order.getState(), OrderStateEnum.NOTPAY.getType())||Objects.equals(order.getState(), OrderStateEnum.TOSUCCESS.getType())
                        ||Objects.equals(order.getState(), OrderStateEnum.WAITING.getType()),
                "错误的订单状态，当前订单状态为" + OrderStateEnum.getByType(order.getState()));

        Cp cp = cpService.getOneById(order.getCpId());
        Assert.notNull(cp, "找不到cp信息");

        if (StringUtils.isNotBlank(spTradeNo)) {
            order.setSpTradeNo(spTradeNo);
        }

        order.setState(OrderStateEnum.SUCCESS.getType());
        order.setFinishTime(new Date());

        //cpAccountService.setOrderSuccess(order);
        qipayTradlogService.setOrderSuccess(order);
        notifyLogService.setOrderSuccess(order, cp);
        //spChannelRuleService.setOrderSuccess(order);
        update(order);
        return order;
    }


    @Override
    @Transactional
    public Order setOrderFail(String tradeNo) {
        Order order = getByTradeNo(tradeNo);
        Assert.notNull(order, "找不到订单信息");

        if (Objects.equals(order.getState(), OrderStateEnum.PAYERROR.getType())) {
            return order;
        }

        order.setState(OrderStateEnum.PAYERROR.getType());
        order.setFinishTime(new Date());
        update(order);

        return order;
    }

    @Override
    @Transactional
    public List<Order> getOrderFinishTimeLargeThenOneDay(int count, int page) {
        Date today = new Date();
        Date endDate = new Date(today.getYear(), today.getMonth(), today.getDate());

        int start = (page - 1) * count;

        OrderExample orderExample = new OrderExample();
        orderExample.setLimit(count);
        orderExample.setOffset(start);
        orderExample.createCriteria().andFinishTimeLessThan(endDate)
                .andStateEqualTo(OrderStateEnum.SUCCESS.getType())
                .andSettleStatusEqualTo(OrderSettleStateEnum.NOTSETTLE.getType());
        List<Order> orders = orderMapper.selectByExample(orderExample);
        return orders;
    }

    @Override
    @Transactional
    public Integer getOrderFinishTimeLargeThenOneDay() {
        Date today = new Date();
        Date endDate = new Date(today.getYear(), today.getMonth(), today.getDate());

        OrderExample orderExample = new OrderExample();
        orderExample.createCriteria().andFinishTimeLessThan(endDate)
                .andStateEqualTo(OrderStateEnum.SUCCESS.getType())
                .andSettleStatusEqualTo(OrderSettleStateEnum.NOTSETTLE.getType());
        return orderMapper.countByExample(orderExample);
    }

    @Override
    @Transactional
    public Order setOrderClose(Order order) {
        Assert.notNull(order, "找不到订单信息");
        if (Objects.equals(order.getState(), OrderStateEnum.SUCCESS.getType())) {
            return order;
        }

        Assert.isTrue(Objects.equals(order.getState(), OrderStateEnum.NOTPAY.getType()),
                "错误的订单状态，当前订单状态为" + OrderStateEnum.getByType(order.getState()));

        order.setState(OrderStateEnum.CLOSE.getType());
        order.setFinishTime(new Date());
        update(order);
        return order;
    }

    @Override
    @Transactional
    public Order selectASp(Order order, ChannelTypeEnum channelTypeEnum) {
        SpChannel spChannel = spChannelService.next(channelTypeEnum, order.getAmount());

        order.setSpId(spChannel.getSpId());
        order.setSpFeeRecharge(spChannel.getFeeRecharge());
        order.setSpFee(spChannel.getFeeRecharge().multiply(
                new BigDecimal(order.getAmount().toString())
        ).intValue());
        return order;
    }

    @Override
    public Order selectASp(Order order, ChannelTypeEnum channelTypeEnum,List<Long>spIds) {
        SpChannel spChannel = spChannelService.next(channelTypeEnum,order.getAmount(),spIds);

        order.setSpId(spChannel.getSpId());
        order.setSpFeeRecharge(spChannel.getFeeRecharge());
        order.setSpFee(spChannel.getFeeRecharge().multiply(
                new BigDecimal(order.getAmount().toString())
        ).intValue());
        return order;
    }

    @Override
    public List<Order> statementBy(Long cpId, String from, String to, Integer channel) {

        return orderMapper.statementBy(cpId, from, to, channel);
    }

    @Override
    public List<OrderStatementVo> statementAllBy(String from, String to, Long cpId, String cpName, Long agentId, String contract, Integer channel) {

        return orderMapper.statementAllBy(from, to, cpId, cpName, agentId, contract, channel);
    }

    @Override
    public List<OrderSpStatementVo> statementSpBy(String from, String to, Long spId, String spName, String service, Integer channel) {
        return orderMapper.statementSpBy(from, to, spId, spName, service, channel);
    }

    @Override
    public Order byState(Byte state) {
        return orderMapper.byState(state);
    }
}
